1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.collect.Multiset.Entry;
23 import com.google.common.primitives.Ints;
24
25 import java.io.Serializable;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Iterator;
29
30 import javax.annotation.Nullable;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 @GwtCompatible(serializable = true, emulated = true)
49 @SuppressWarnings("serial")
50
51 public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
52 implements Multiset<E> {
53
54 private static final ImmutableMultiset<Object> EMPTY =
55 new RegularImmutableMultiset<Object>(ImmutableMap.<Object, Integer>of(), 0);
56
57
58
59
60 @SuppressWarnings("unchecked")
61 public static <E> ImmutableMultiset<E> of() {
62 return (ImmutableMultiset<E>) EMPTY;
63 }
64
65
66
67
68
69
70
71 @SuppressWarnings("unchecked")
72 public static <E> ImmutableMultiset<E> of(E element) {
73 return copyOfInternal(element);
74 }
75
76
77
78
79
80
81
82 @SuppressWarnings("unchecked")
83 public static <E> ImmutableMultiset<E> of(E e1, E e2) {
84 return copyOfInternal(e1, e2);
85 }
86
87
88
89
90
91
92
93 @SuppressWarnings("unchecked")
94 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3) {
95 return copyOfInternal(e1, e2, e3);
96 }
97
98
99
100
101
102
103
104 @SuppressWarnings("unchecked")
105 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4) {
106 return copyOfInternal(e1, e2, e3, e4);
107 }
108
109
110
111
112
113
114
115 @SuppressWarnings("unchecked")
116 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4, E e5) {
117 return copyOfInternal(e1, e2, e3, e4, e5);
118 }
119
120
121
122
123
124
125
126 @SuppressWarnings("unchecked")
127 public static <E> ImmutableMultiset<E> of(
128 E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
129 return new Builder<E>()
130 .add(e1)
131 .add(e2)
132 .add(e3)
133 .add(e4)
134 .add(e5)
135 .add(e6)
136 .add(others)
137 .build();
138 }
139
140
141
142
143
144
145
146
147
148
149
150 public static <E> ImmutableMultiset<E> copyOf(E[] elements) {
151 return copyOf(Arrays.asList(elements));
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 public static <E> ImmutableMultiset<E> copyOf(
172 Iterable<? extends E> elements) {
173 if (elements instanceof ImmutableMultiset) {
174 @SuppressWarnings("unchecked")
175 ImmutableMultiset<E> result = (ImmutableMultiset<E>) elements;
176 if (!result.isPartialView()) {
177 return result;
178 }
179 }
180
181 Multiset<? extends E> multiset = (elements instanceof Multiset)
182 ? Multisets.cast(elements)
183 : LinkedHashMultiset.create(elements);
184
185 return copyOfInternal(multiset);
186 }
187
188 private static <E> ImmutableMultiset<E> copyOfInternal(E... elements) {
189 return copyOf(Arrays.asList(elements));
190 }
191
192 private static <E> ImmutableMultiset<E> copyOfInternal(
193 Multiset<? extends E> multiset) {
194 return copyFromEntries(multiset.entrySet());
195 }
196
197 static <E> ImmutableMultiset<E> copyFromEntries(
198 Collection<? extends Entry<? extends E>> entries) {
199 long size = 0;
200 ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
201 for (Entry<? extends E> entry : entries) {
202 int count = entry.getCount();
203 if (count > 0) {
204
205
206 builder.put(entry.getElement(), count);
207 size += count;
208 }
209 }
210
211 if (size == 0) {
212 return of();
213 }
214 return new RegularImmutableMultiset<E>(
215 builder.build(), Ints.saturatedCast(size));
216 }
217
218
219
220
221
222
223
224
225
226
227
228 public static <E> ImmutableMultiset<E> copyOf(
229 Iterator<? extends E> elements) {
230 Multiset<E> multiset = LinkedHashMultiset.create();
231 Iterators.addAll(multiset, elements);
232 return copyOfInternal(multiset);
233 }
234
235 ImmutableMultiset() {}
236
237 @Override public UnmodifiableIterator<E> iterator() {
238 final Iterator<Entry<E>> entryIterator = entrySet().iterator();
239 return new UnmodifiableIterator<E>() {
240 int remaining;
241 E element;
242
243 @Override
244 public boolean hasNext() {
245 return (remaining > 0) || entryIterator.hasNext();
246 }
247
248 @Override
249 public E next() {
250 if (remaining <= 0) {
251 Entry<E> entry = entryIterator.next();
252 element = entry.getElement();
253 remaining = entry.getCount();
254 }
255 remaining--;
256 return element;
257 }
258 };
259 }
260
261 @Override
262 public boolean contains(@Nullable Object object) {
263 return count(object) > 0;
264 }
265
266 @Override
267 public boolean containsAll(Collection<?> targets) {
268 return elementSet().containsAll(targets);
269 }
270
271
272
273
274
275
276
277 @Deprecated
278 @Override
279 public final int add(E element, int occurrences) {
280 throw new UnsupportedOperationException();
281 }
282
283
284
285
286
287
288
289 @Deprecated
290 @Override
291 public final int remove(Object element, int occurrences) {
292 throw new UnsupportedOperationException();
293 }
294
295
296
297
298
299
300
301 @Deprecated
302 @Override
303 public final int setCount(E element, int count) {
304 throw new UnsupportedOperationException();
305 }
306
307
308
309
310
311
312
313 @Deprecated
314 @Override
315 public final boolean setCount(E element, int oldCount, int newCount) {
316 throw new UnsupportedOperationException();
317 }
318
319 @Override public boolean equals(@Nullable Object object) {
320 return Multisets.equalsImpl(this, object);
321 }
322
323 @Override public int hashCode() {
324 return Sets.hashCodeImpl(entrySet());
325 }
326
327 @Override public String toString() {
328 return entrySet().toString();
329 }
330
331 private transient ImmutableSet<Entry<E>> entrySet;
332
333 @Override
334 public ImmutableSet<Entry<E>> entrySet() {
335 ImmutableSet<Entry<E>> es = entrySet;
336 return (es == null) ? (entrySet = createEntrySet()) : es;
337 }
338
339 private final ImmutableSet<Entry<E>> createEntrySet() {
340 return isEmpty() ? ImmutableSet.<Entry<E>>of() : new EntrySet();
341 }
342
343 abstract Entry<E> getEntry(int index);
344
345 private final class EntrySet extends ImmutableSet<Entry<E>> {
346 @Override
347 boolean isPartialView() {
348 return ImmutableMultiset.this.isPartialView();
349 }
350
351 @Override
352 public UnmodifiableIterator<Entry<E>> iterator() {
353 return asList().iterator();
354 }
355
356 @Override
357 ImmutableList<Entry<E>> createAsList() {
358 return new ImmutableAsList<Entry<E>>() {
359 @Override
360 public Entry<E> get(int index) {
361 return getEntry(index);
362 }
363
364 @Override
365 ImmutableCollection<Entry<E>> delegateCollection() {
366 return EntrySet.this;
367 }
368 };
369 }
370
371 @Override
372 public int size() {
373 return elementSet().size();
374 }
375
376 @Override
377 public boolean contains(Object o) {
378 if (o instanceof Entry) {
379 Entry<?> entry = (Entry<?>) o;
380 if (entry.getCount() <= 0) {
381 return false;
382 }
383 int count = count(entry.getElement());
384 return count == entry.getCount();
385 }
386 return false;
387 }
388
389 @Override
390 public int hashCode() {
391 return ImmutableMultiset.this.hashCode();
392 }
393
394
395
396
397 Object writeReplace() {
398 return new EntrySetSerializedForm<E>(ImmutableMultiset.this);
399 }
400
401 private static final long serialVersionUID = 0;
402 }
403
404 static class EntrySetSerializedForm<E> implements Serializable {
405 final ImmutableMultiset<E> multiset;
406
407 EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
408 this.multiset = multiset;
409 }
410
411 Object readResolve() {
412 return multiset.entrySet();
413 }
414 }
415
416 private static class SerializedForm implements Serializable {
417 final Object[] elements;
418 final int[] counts;
419
420 SerializedForm(Multiset<?> multiset) {
421 int distinct = multiset.entrySet().size();
422 elements = new Object[distinct];
423 counts = new int[distinct];
424 int i = 0;
425 for (Entry<?> entry : multiset.entrySet()) {
426 elements[i] = entry.getElement();
427 counts[i] = entry.getCount();
428 i++;
429 }
430 }
431
432 Object readResolve() {
433 LinkedHashMultiset<Object> multiset =
434 LinkedHashMultiset.create(elements.length);
435 for (int i = 0; i < elements.length; i++) {
436 multiset.add(elements[i], counts[i]);
437 }
438 return ImmutableMultiset.copyOf(multiset);
439 }
440
441 private static final long serialVersionUID = 0;
442 }
443
444
445
446 Object writeReplace() {
447 return new SerializedForm(this);
448 }
449
450
451
452
453
454 public static <E> Builder<E> builder() {
455 return new Builder<E>();
456 }
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476 public static class Builder<E> extends ImmutableCollection.Builder<E> {
477 final Multiset<E> contents;
478
479
480
481
482
483 public Builder() {
484 this(LinkedHashMultiset.<E>create());
485 }
486
487 Builder(Multiset<E> contents) {
488 this.contents = contents;
489 }
490
491
492
493
494
495
496
497
498 @Override public Builder<E> add(E element) {
499 contents.add(checkNotNull(element));
500 return this;
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516 public Builder<E> addCopies(E element, int occurrences) {
517 contents.add(checkNotNull(element), occurrences);
518 return this;
519 }
520
521
522
523
524
525
526
527
528
529
530
531 public Builder<E> setCount(E element, int count) {
532 contents.setCount(checkNotNull(element), count);
533 return this;
534 }
535
536
537
538
539
540
541
542
543
544 @Override public Builder<E> add(E... elements) {
545 super.add(elements);
546 return this;
547 }
548
549
550
551
552
553
554
555
556
557
558 @Override public Builder<E> addAll(Iterable<? extends E> elements) {
559 if (elements instanceof Multiset) {
560 Multiset<? extends E> multiset = Multisets.cast(elements);
561 for (Entry<? extends E> entry : multiset.entrySet()) {
562 addCopies(entry.getElement(), entry.getCount());
563 }
564 } else {
565 super.addAll(elements);
566 }
567 return this;
568 }
569
570
571
572
573
574
575
576
577
578 @Override public Builder<E> addAll(Iterator<? extends E> elements) {
579 super.addAll(elements);
580 return this;
581 }
582
583
584
585
586
587 @Override public ImmutableMultiset<E> build() {
588 return copyOf(contents);
589 }
590 }
591 }